﻿#include "GY_CPUCounterTimer.h"
#include <QLibrary>
#include <QDebug>

GY_CPUCounterTimer::GY_CPUCounterTimer(QObject *parent) : QObject(parent)
{
    //初始化日期、时间、速率、间隔
    m_CurrentDate=QDate(2000,1,1);
    m_CurrentTime=0;
    m_TimeSpeed=1;
    m_TimeInter=1000000;
    m_pThread=nullptr;
    //初始化运行状态、设备状态
    isRuning=false;
    devIsOk=false;

    //默认工作模式为：被动模式
    m_TimerMode=PassivityTimer;

#ifdef WIN32
    QLibrary counterLibrary("Kernel32.dll",this);
    if(!counterLibrary.load())
    {
        return;
    }

    m_Fun_QueryPerformanceCounter=(QueryPerformanceCounter)counterLibrary.resolve("QueryPerformanceCounter");
    m_Fun_QueryPerformanceFrequency=(QueryPerformanceFrequency)counterLibrary.resolve("QueryPerformanceFrequency");
    if(!m_Fun_QueryPerformanceCounter||!m_Fun_QueryPerformanceFrequency)
    {
        return;
    }

    //获取计数器频率
    m_Fun_QueryPerformanceFrequency(&m_CounterFrequency);
    devIsOk=true;
#endif

    //初始化线程：周期发送当前日期和时间
    m_pThread = new QThread;
    this->moveToThread(m_pThread);
    connect(m_pThread,&QThread::started,this,&GY_CPUCounterTimer::timeOutEvent);
    connect(m_pThread, &QThread::finished, m_pThread, &QThread::deleteLater);
}

//析构
GY_CPUCounterTimer::~GY_CPUCounterTimer()
{
    //关闭线程
    m_pThread->quit();
    m_pThread->wait();
    m_pThread=nullptr;
}

/**
 * @brief timeOut 时间间隔事件：主动模式下触发
 */
void GY_CPUCounterTimer::timeOutEvent()
{
    //上一次的超时值
    m_LastTimeOutTime = m_CurrentTime;

    while (true) {
        m_ThreadMutex.lock();
        m_Fun_QueryPerformanceCounter(&m_CurrentCount);
        m_TimeMutex.lock();
        //获得从开始到当前走了多少时间：单位为微妙
        quint64 runTime = static_cast<quint64>(((m_CurrentCount.QuadPart - m_LastCount.QuadPart)*1000000.0)/static_cast<double>(m_CounterFrequency.QuadPart));
        m_CurrentTime = static_cast<quint64>(m_LastTimeOutTime + runTime * m_TimeSpeed);
        m_TimeMutex.unlock();

        qint64 time = static_cast<qint64>(m_CurrentTime);
        m_DateMutex.lock();
        QDate date = m_CurrentDate;
        m_DateMutex.unlock();

        //时间和日期的转换
        timeConvertDate(date,time);

        if(m_TimeSpeed > 0){ //如果是正常播放或快进
            if(m_CurrentTime - m_LastTimeOutTime > m_TimeInter){ //如果当前时间比上一次间隔已经大于时间间隔，则发出信号
                emit timeOutSiganl(m_CurrentDate,m_CurrentTime);
                m_LastTimeOutTime = m_CurrentTime; //将当前时间重置为上次时间
                m_LastCount.QuadPart = m_CurrentCount.QuadPart;  //将当前计数设置为上一次计数
            }
        }else{ //如果是快退
            if(m_LastTimeOutTime - m_CurrentTime > m_TimeInter){ //如果快退时间大于间隔，则发出信号
                emit timeOutSiganl(m_CurrentDate,m_CurrentTime);
                m_LastTimeOutTime = m_CurrentTime; //将当前时间重置为上次时间
                m_LastCount.QuadPart = m_CurrentCount.QuadPart;  //将当前计数设置为上一次计数
            }
        }
        m_ThreadMutex.unlock();
    }
}

/**
 * @brief GY_CPUCounterTimer::timeConvertDate 时间日期转换
 * @param date 日期
 * @param time 时间
 */
void GY_CPUCounterTimer::timeConvertDate(QDate date, qint64 time)
{
    //如果时间大于一天微秒数说明到了第二天
    if(time>=ONE_DATE_MICROSECONDCOUNT)
    {
        time-=ONE_DATE_MICROSECONDCOUNT;
        m_TimeMutex.lock();
        m_CurrentTime = static_cast<quint64>(time);
        m_TimeMutex.unlock();
        qint64 addDay = 1;
        date=date.addDays(addDay);
        m_DateMutex.lock();
        m_CurrentDate = date;
        m_DateMutex.unlock();
    }

    //如果时间小于0说明回到了上一天
    else if(time<0)
    {
        time+=ONE_DATE_MICROSECONDCOUNT;
        m_TimeMutex.lock();
        m_CurrentTime = static_cast<quint64>(time);
        m_TimeMutex.unlock();
        qint64 addDay = -1;
        date=date.addDays(addDay);
        m_DateMutex.lock();
        m_CurrentDate = date;
        m_DateMutex.unlock();
    }
}

/**
 * @brief startTimer 开始计时：被动模式
 * @param timeInter 计时器间隔
 */
void GY_CPUCounterTimer::startTimer(const quint32 timeInter)
{
    if(isRuning)
    {
        return;
    }

    //工作模式为：被动模式
    m_TimerMode = PassivityTimer;
    m_TimeInter = timeInter;
    isRuning = true;

    //!获取当前计数器次数
    m_Fun_QueryPerformanceCounter(&m_CurrentCount);
}

/**
 * @brief GY_CPUCounterTimer::startTimer 开始计时：主动模式
 */
void GY_CPUCounterTimer::startTimer()
{
    if(isRuning){
        return;
    }

    //工作模式为：主动模式
    m_TimerMode = InitiativeTimer;
    isRuning = true;

    //获取当前计数器次数
    m_Fun_QueryPerformanceCounter(&m_LastCount);
    m_CurrentCount.QuadPart=0;

    //线程解锁
    m_ThreadMutex.tryLock();
    m_ThreadMutex.unlock();

    //启动线程
    m_pThread->start();
}

/**
 * @brief stopTimer
 * 停止计时器
 */
void GY_CPUCounterTimer::stopTimer()
{
    if(!isRuning)
    {
        return;
    }
    isRuning=false;
    //将之前的m_curentCount赋给lastCount，准备重新获取当前count
    m_LastCount = m_CurrentCount;
    //获取当前计数器次数
    m_Fun_QueryPerformanceCounter(&m_CurrentCount);

    //获得从开始到当前走了多少时间：单位为微妙
    quint64 runTime = static_cast<quint64>(((m_CurrentCount.QuadPart - m_LastCount.QuadPart)*1000000.0)/static_cast<double>(m_CounterFrequency.QuadPart));
    m_TimeMutex.lock();
    m_CurrentTime = static_cast<quint64>(m_CurrentTime + runTime * m_TimeSpeed);
    m_TimeMutex.unlock();

    qint64 time = static_cast<qint64>(m_CurrentTime);
    m_DateMutex.lock();
    QDate date = m_CurrentDate;
    m_DateMutex.unlock();

    //时间和日期的转换
    timeConvertDate(date,time);

    if(m_TimerMode == InitiativeTimer)
    {
        m_ThreadMutex.lock();
    }
}

/**
 * @brief getCurrentTime 获取当前时间
 * @return 返回当前计时时间
 */
quint64 GY_CPUCounterTimer::getCurrentTime()
{
    if(m_TimerMode == PassivityTimer && isRuning)
    {
        //将之前的m_curentCount赋给lastCount，准备重新获取当前count
        m_LastCount = m_CurrentCount;

        //获取当前计数器次数
        m_Fun_QueryPerformanceCounter(&m_CurrentCount);
        //获得从开始到当前走了多少时间：单位为微妙
        quint64 runTime = static_cast<quint64>(((m_CurrentCount.QuadPart - m_LastCount.QuadPart)*1000000.0)/static_cast<double>(m_CounterFrequency.QuadPart));
        m_TimeMutex.lock();
        m_CurrentTime = static_cast<quint64>(m_CurrentTime + runTime * m_TimeSpeed);
        m_TimeMutex.unlock();
    }

    //获取当前日期和时间
    m_DateMutex.lock();
    QDate date = m_CurrentDate;
    m_DateMutex.unlock();
    m_TimeMutex.lock();
    qint64 time = static_cast<qint64>(m_CurrentTime);
    m_TimeMutex.unlock();

    //时间日期转换
    timeConvertDate(date,time);

    return static_cast<quint64>(time);
}

/**
 * @brief getCurrentDate  获取当前日期
 * @return 返回日期
 */
QDate GY_CPUCounterTimer::getCurrentDate()
{
    QDate date;
    m_DateMutex.lock();
    date = m_CurrentDate;
    m_DateMutex.unlock();
    return date;
}

/**
 * @brief setCurrentTime 设置当前时间
 * @param time 当前时间
 */
void GY_CPUCounterTimer::setCurrentTime(const quint64 time)
{
    //判定如果输入的时间超过24小时视为无效
    if(time>ONE_DATE_MICROSECONDCOUNT)
    {
        return;
    }
    m_TimeMutex.lock();
    m_CurrentTime=time;
    m_TimeMutex.unlock();
}

/**
 * @brief setCurrentDate 设置当前日期
 * @param date 日期
 */
void GY_CPUCounterTimer::setCurrentDate(const QDate &date)
{
    m_DateMutex.lock();
    m_CurrentDate = date;
    m_DateMutex.unlock();
}

/**
 * @brief setTimerSpeed  设置计时器速率
 * @param timeSpeed 计时速率
 */
void GY_CPUCounterTimer::setTimerSpeed(const double timeSpeed)
{
    m_TimeMutex.lock();
    m_TimeSpeed=timeSpeed;
    m_TimeMutex.unlock();
}

/**
 * @brief GY_CPUCounterTimer::uintToHourMinSec 时间转换
 * @param time uint时间
 * @return 时分秒格式的时间
 */
QString GY_CPUCounterTimer::uintToHourMinSec(quint32 time)
{
    QString timeStr;
    int secTemp = time/1000000;
    int hour = secTemp/3600;
    int min = (secTemp%3600)/60;
    int sec = secTemp%3600%60;
    int micro = secTemp%1000000;

    timeStr = QString::number(hour)+":"+QString::number(min)+":"+QString::number(sec)+"."+QString::number(micro);
    return timeStr;
}
